#include "app_serial.h"
#include <stdlib.h>
#include "app_bluetooth.h"
#include <unistd.h>
#include "log/log.h"

/**
 * @brief 设置串口的阻塞模式
 *
 * @param block_mode 1 阻塞 0 非阻塞
 * @return int 0成功 -1失败
 */
static int app_serial_setBlockMode(SerialDevice *dev, int block_mode)
{
    // 1. 获取串口属性
    struct termios options;
    if (tcgetattr(dev->super.fd, &options) < 0)
    {
        log_error("Failed to get serial device attributes");
        return -1;
    }

    // 2. 修改属性
    options.c_cc[VTIME] = 0;
    if (block_mode)
    {
        options.c_cc[VMIN] = 1;
    }
    else
    {
        options.c_cc[VMIN] = 0;
    }

    // 3. 写回串口属性
    if (tcsetattr(dev->super.fd, TCSAFLUSH, &options) < 0)
    {
        log_error("Failed to set serial device attributes");
        return -1;
    }
    return 0;
}

/**
 * @brief 将设备设置为原始模式
 *
 * @param dev
 * @return int
 */
static int app_serial_setRaw(SerialDevice *dev)
{
    // 1. 获取串口属性
    struct termios options;
    if (tcgetattr(dev->super.fd, &options) < 0)
    {
        log_error("Failed to get serial device attributes");
        return -1;
    }

    // 2. 修改属性
    cfmakeraw(&options);

    // 3. 写回串口属性
    if (tcsetattr(dev->super.fd, TCSAFLUSH, &options) < 0)
    {
        log_error("Failed to set serial device attributes");
        return -1;
    }
    return 0;
}

SerialDevice *app_serial_init(char *dev_name)
{
    Device *dev = app_device_init(dev_name);
    if (!dev)
    {
        goto DEV_INIT_FAIL;
    }

    void *temp = realloc(dev, sizeof(SerialDevice));
    if (!temp)
    {
        app_device_deinit(dev);
        goto DEV_INIT_FAIL;
    }

    SerialDevice *serial_dev = (SerialDevice *)temp;

    if (app_serial_setBaudrate(serial_dev, BAUD_115200) < 0)
    {
        log_error("Failed to set baudrate");
        goto SERIAL_DEV_INIT_FAIL;
    }
    if (app_serial_setDataBits(serial_dev, DATA_BITS_8) < 0)
    {
        log_error("Failed to set data bits");
        goto SERIAL_DEV_INIT_FAIL;
    }
    if (app_serial_setStopBits(serial_dev, STOP_BITS_1) < 0)
    {
        log_error("Failed to set stop bits");
        goto SERIAL_DEV_INIT_FAIL;
    }
    if (app_serial_setParity(serial_dev, PARITY_NONE) < 0)
    {
        log_error("Failed to set parity");
        goto SERIAL_DEV_INIT_FAIL;
    }

    if (app_serial_setRaw(serial_dev) < 0)
    {
        log_error("Failed to set parity");
        goto SERIAL_DEV_INIT_FAIL;
    }

    if (tcflush(serial_dev->super.fd, TCIOFLUSH) < 0)
    {
        log_error("Failed to flush serial device");
        goto SERIAL_DEV_INIT_FAIL;
    }

    log_info("Serial device initialized");
    return serial_dev;
SERIAL_DEV_INIT_FAIL:
    app_device_deinit((Device *)serial_dev);
DEV_INIT_FAIL:
    return NULL;
}

int app_serial_setBaudrate(SerialDevice *dev, Baudrate baudrate)
{
    // 1. 获取串口属性
    struct termios options;
    if (tcgetattr(dev->super.fd, &options) < 0)
    {
        log_error("Failed to get serial device attributes");
        return -1;
    }

    // 2. 修改属性
    if (cfsetspeed(&options, baudrate) < 0)
    {
        log_error("Failed to set serial device baudrate");
        return -1;
    }

    // 3. 写回串口属性
    if (tcsetattr(dev->super.fd, TCSAFLUSH, &options) < 0)
    {
        log_error("Failed to set serial device attributes");
        return -1;
    }
    return 0;
}

int app_serial_setDataBits(SerialDevice *dev, DataBits data_bits)
{
    // 1. 获取串口属性
    struct termios options;
    if (tcgetattr(dev->super.fd, &options) < 0)
    {
        log_error("Failed to get serial device attributes");
        return -1;
    }

    // 2. 修改属性
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= data_bits;

    // 3. 写回串口属性
    if (tcsetattr(dev->super.fd, TCSAFLUSH, &options) < 0)
    {
        log_error("Failed to set serial device attributes");
        return -1;
    }
    return 0;
}

int app_serial_setStopBits(SerialDevice *dev, StopBits stop_bits)
{
    // 1. 获取串口属性
    struct termios options;
    if (tcgetattr(dev->super.fd, &options) < 0)
    {
        log_error("Failed to get serial device attributes");
        return -1;
    }

    // 2. 修改属性
    options.c_cflag &= ~CSTOPB;
    options.c_cflag |= stop_bits;

    // 3. 写回串口属性
    if (tcsetattr(dev->super.fd, TCSAFLUSH, &options) < 0)
    {
        log_error("Failed to set serial device attributes");
        return -1;
    }
    return 0;
}

int app_serial_setParity(SerialDevice *dev, Parity parity)
{
    // 1. 获取串口属性
    struct termios options;
    if (tcgetattr(dev->super.fd, &options) < 0)
    {
        log_error("Failed to get serial device attributes");
        return -1;
    }

    // 2. 修改属性
    options.c_cflag &= ~(PARENB | PARODD);
    options.c_cflag |= parity;

    // 3. 写回串口属性
    if (tcsetattr(dev->super.fd, TCSAFLUSH, &options) < 0)
    {
        log_error("Failed to set serial device attributes");
        return -1;
    }
    return 0;
}

int app_serial_setConnectionType(SerialDevice *dev, ConnectionType type)
{
    switch (type)
    {
    case TYPE_BT:
        // 对蓝牙模块初始化，同时设置dev->func的回调
        // 设置波特率，首先尝试以9600波特率握手，并设置115200波特率；
        // 如果握手失败则直接切换到115200波特率
        app_serial_setBlockMode(dev, 0);
        app_serial_setBaudrate(dev, BAUD_9600);
        tcflush(dev->super.fd, TCIOFLUSH);

        if (app_bluetooth_stat((Device *)dev) == 0)
        {
            if (app_bluetooth_setBaudrate((Device *)dev, BAUD_115200) < 0)
            {
                log_error("Failed to set bt baudrate");
                return -1;
            }
            if (app_bluetooth_reset((Device *)dev) < 0)
            {
                log_error("Failed to reset bt");
                return -1;
            }
        }

        // 等待蓝牙模块重启完成
        sleep(2);
        // 将自己的波特率重新设置为115200
        app_serial_setBaudrate(dev, BAUD_115200);
        tcflush(dev->super.fd, TCIOFLUSH);

        if (app_bluetooth_setNetID((Device *)dev, "1234") < 0)
        {
            log_error("Failed to set netid");
            return -1;
        }
        if (app_bluetooth_setMaddr((Device *)dev, "0001") < 0)
        {
            log_error("Failed to set maddr");
            return -1;
        }

        app_serial_setBlockMode(dev, 1);
        tcflush(dev->super.fd, TCIOFLUSH);

        // 设置回调
        dev->super.func->postRead = app_bluetooth_postRead;
        dev->super.func->preWrite = app_bluetooth_preWrite;
        dev->super.type = TYPE_BT;
        log_info("BT init success");
        break;

    default:
        break;
    }
    return 0;
}
